using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace testLine
{
	/// <summary>
	/// A control will draw a line.
	/// </summary>

	[Designer(typeof(LabelLineDesigner))]//set the Designer
	public class LabelLine : System.Windows.Forms.Control
	{
		
		#region Private vars
		///<summary>
		///Direction of the Line
		///</summary>
		private LineStyles _LineStyle = LineStyles.Horizontal;
		private float widthInHorizontal = 0;
		private float heightInVertical  = 0;
		#endregion

		#region Constructor
		public LabelLine():base()
		{
			
			this.Name = "HLine";
			this.Size = new System.Drawing.Size(100, 5);

			//Set control style
			SetStyle(ControlStyles.ResizeRedraw ,true);
			SetStyle(ControlStyles.DoubleBuffer  | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint,true);

		}

		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				this.brushText.Dispose();
				this.cellBounds = System.Drawing.RectangleF.Empty;
				this.penDimGray.Dispose();
				penWhite.Dispose();
			}
			base.Dispose (disposing);
		}


		~LabelLine()
		{
			Dispose();

		}
		#endregion
		
		#region hided properties
		[Browsable(false)]
		public new System.Drawing.Size Size
		{
			get
			{
				return base.Size;
			}
			set
			{
				base.Size = value;
			}
		}
		#endregion

		#region customize properties
		[
		DefaultValue(100),
		Description("LineLength"),
		Browsable(true)
		]
		public int LineLength
		{
			get { 
				if (this.LineStyle == LineStyles.Horizontal)
					return this.Width;
				else 
					return this.Height;
			}
			set { 
				if (this.LineStyle == LineStyles.Horizontal)
					this.Width = value;
				else
					this.Height = value;
			}
		}

		[Category("Appearance"),
		DefaultValue(LineStyles.Horizontal),
		Description("LineStyles")
		]
		public LineStyles LineStyle
		{
			get{ return this._LineStyle;}
			set
			{
				if (value == this._LineStyle) return;

				//After change the direction, exchange the height and width.
				int iTmp = this.Width;
				this.Width = this.Height;
				this.Height = iTmp;

				this._LineStyle = value;

				this.Invalidate();
				
			}
		}


		private TextAlignment _TextAlign = TextAlignment.LeftOrTop;
		[
		Browsable(true),
		DefaultValue(TextAlignment.LeftOrTop),
		Description("Get/Set TextAlign")
		]
		public TextAlignment TextAlign
		{
			get { return this._TextAlign; }
			set {
				if (value == this._TextAlign) return;

				this._TextAlign = value;

				this.Invalidate();
			}
		}

		[DefaultValue(typeof(Color),"ControlText"),Description("ForeColor")]
		public override Color ForeColor
		{
			get
			{
				return base.ForeColor;
			}
			set
			{
				this.brushText.Color = value;
				base.ForeColor = value;
				
			}
		}

		#endregion

		#region Override OnPaint
		/// <summary>
		/// Override OnPaint to implement the functionality
		/// </summary>
		/// <param name="e"></param>
		protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
		{
			base.OnPaint(e);

			MeasureSize(e.Graphics,this.Text);

			DrawContent(e.Graphics);
			
		}
		#endregion

		#region Set control size
		private void MeasureSize(Graphics g,string strText)
		{
			Size size = new Size(5,5);

			Size tmpSize = new Size(0,0);
			
			heightInVertical = 0;
			for(int i=0;i<strText.Length;i++)
			{
				tmpSize = g.MeasureString(strText[i].ToString(),this.Font).ToSize();

				if (tmpSize.Width > size.Width) size.Width = tmpSize.Width;
				if (tmpSize.Height > size.Height) size.Height = tmpSize.Height;
				heightInVertical += tmpSize.Height;
			}

			widthInHorizontal = g.MeasureString(strText,this.Font).Width;

			if (this.LineStyle == LineStyles.Horizontal)
				this.Size = new Size(this.Size.Width, size.Height);
			else
				this.Size = new Size(size.Width,this.Size.Height);

		}
		#endregion

		#region Draw content, include line and text.
		private SolidBrush brushText = new SolidBrush(Color.Black);
		private StringFormat stringFormat = new StringFormat();
		private RectangleF cellBounds = new RectangleF(0,0,0,0);
		private void DrawContent(Graphics g)
		{
		
			if (this.LineStyle == LineStyles.Horizontal)
			{
				cellBounds.X = 0;
				cellBounds.Y = 2;
				cellBounds.Width = this.Width;
				cellBounds.Height = this.Height;

				stringFormat.LineAlignment = StringAlignment.Center;

				switch (this.TextAlign)
				{
					case TextAlignment.LeftOrTop:
						stringFormat.Alignment = StringAlignment.Near;
						DrawLine(g,(int)widthInHorizontal,this.Height / 2,this.Width,this.Height / 2);
						break;
					case TextAlignment.CenterOrMiddle:
						stringFormat.Alignment = StringAlignment.Center;
						DrawLine(g,0,this.Height / 2,(this.Width - (int)widthInHorizontal) / 2,this.Height / 2);
						DrawLine(g,(this.Width + (int)widthInHorizontal) / 2,this.Height / 2,this.Width,this.Height / 2);
						break;
					case TextAlignment.RightOrBottom:
						stringFormat.Alignment = StringAlignment.Far;
						DrawLine(g,0,this.Height / 2,this.Width - (int)widthInHorizontal,this.Height / 2);
						break;
				}

				g.DrawString(this.Text,this.Font, brushText,cellBounds,stringFormat);
			}
			else
			{
				cellBounds.X = 1;
				cellBounds.Y = 0;
				cellBounds.Width = this.Width;
				cellBounds.Height = heightInVertical;

				stringFormat.LineAlignment = StringAlignment.Center;
				stringFormat.Alignment = StringAlignment.Center;

				switch (this.TextAlign)
				{
					case TextAlignment.LeftOrTop:

						DrawLine(g,this.Width / 2,(int)heightInVertical,this.Width / 2,this.Height);
						break;
					case TextAlignment.CenterOrMiddle:
						DrawLine(g,this.Width / 2,0,this.Width / 2,(this.Height - (int)heightInVertical) / 2);

						cellBounds.Y = (this.Height - (int)heightInVertical) / 2 + 2;
					
						DrawLine(g,this.Width / 2,(this.Height + (int)heightInVertical) / 2,this.Width / 2,this.Height);
						break;
					case TextAlignment.RightOrBottom:
						DrawLine(g,this.Width / 2,0,this.Width / 2,this.Height - (int)heightInVertical);

						cellBounds.Y = this.Height - (int)heightInVertical + 4;

						break;


				}

				for(int i=0;i<this.Text.Length;i++)
				{
					cellBounds.Size = g.MeasureString(Text[i].ToString(),this.Font).ToSize();
				
					g.DrawString(Text[i].ToString(),this.Font,brushText,cellBounds,stringFormat);
					cellBounds.Y += cellBounds.Height;
				
				
				}
			}
		}
		#endregion

		#region Draw line
		Pen penDimGray = new Pen(Color.DimGray,1);
		Pen penWhite = new Pen(Color.White,1);
		private void DrawLine(Graphics g,int x1,int y1,int x2,int y2)
		{
			//Horizontal line
			if (LineStyle == LineStyles.Horizontal)
			{
				g.DrawLine(penDimGray,x1,y1,x2,y2);

				g.DrawLine(penWhite,x1,y1 + 1,x2,y2 + 1);
			}
			else//Vertical line
			{
				g.DrawLine(new Pen(Color.DimGray,1),x1,y1,x2,y2);

				g.DrawLine(new Pen(Color.White,1),x1 + 1,y1,x2 + 1,y2);
			}

		}
		#endregion
	}

	

	#region LineStyles enum
	/// <summary>
	/// Line Direction
	/// </summary>
	public enum LineStyles
	{
		/// <summary>
		/// Horizontal Line
		/// </summary>
		Horizontal,
		/// <summary>
		/// Vertical Line
		/// </summary>
		Vertical
	}
	#endregion


	#region TextAlignment enum
	/// <summary>
	/// Text Position
	/// </summary>
	public enum TextAlignment
	{
		/// <summary>
		/// LeftOrTop
		/// </summary>
		LeftOrTop,
		/// <summary>
		/// CenterOrMiddle
		/// </summary>
		CenterOrMiddle,
		/// <summary>
		/// RightOrBottom
		/// </summary>
		RightOrBottom
	}
	#endregion
}
